﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Configuration;
using Abp.Notifications;
using Abp.Runtime.Session;
using LeadThing.AbpZeroTemplate.Notifications.Dto;
using Abp.Domain.Repositories;
using LeadThing.AbpZeroTemplate.Authorization.Users;
using Abp;
using System.Data.Entity;
using Abp.Linq.Extensions;
using static LeadThing.AbpZeroTemplate.Configuration.AppSettings;
using LeadThing.AbpZeroTemplate.Authorization.Roles.Dto;
using LeadThing.AbpZeroTemplate.Authorization.Roles;
using System.Text;
using System.Net;
using LeadThing.AbpZeroTemplate.Common.Html;

namespace LeadThing.AbpZeroTemplate.Notifications
{

    public class NotificationAppService : AbpZeroTemplateAppServiceBase, INotificationAppService
    {
        private readonly INotificationDefinitionManager _notificationDefinitionManager;
        private readonly IUserNotificationManager _userNotificationManager;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly IRepository<User, long> _userRepository;//用户
        private readonly IRepository<TenantNotificationInfo, Guid> _tenantNotificationRepository;
        private readonly IRepository<UserNotificationInfo, Guid> _userNotificationRepository;
        private readonly IAppNotifier _appNotifier;//通知
        private readonly IRoleAppService _roleService;//角色

        public NotificationAppService(
            INotificationDefinitionManager notificationDefinitionManager,
            IUserNotificationManager userNotificationManager,
            INotificationSubscriptionManager notificationSubscriptionManager,
            IRepository<User, long> userRepository,
            IRepository<TenantNotificationInfo, Guid> tenantNotificationRepository,
            IRepository<UserNotificationInfo, Guid> userNotificationRepository,
            IAppNotifier appNotifier,
            IRoleAppService roleService)
        {
            _notificationDefinitionManager = notificationDefinitionManager;
            _userNotificationManager = userNotificationManager;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _userRepository = userRepository;
            _tenantNotificationRepository = tenantNotificationRepository;
            _userNotificationRepository = userNotificationRepository;
            _appNotifier = appNotifier;
            _roleService = roleService;
        }

        #region 实体的自定义扩展方法

        /// <summary>
        /// 根据查询条件获取消息通知分页列表
        /// </summary>
        [AbpAuthorize]
        public async Task<GetNotificationsExtendOutput> GetPagedUserNotificationsAsync(GetUserNotificationsInput input)
        {
            var query = from userNotificationInfo in _userNotificationRepository.GetAll()
                        join tenantNotificationInfo in _tenantNotificationRepository.GetAll() on userNotificationInfo.TenantNotificationId equals tenantNotificationInfo.Id
                        orderby tenantNotificationInfo.CreationTime descending
                        select new { userNotificationInfo, tenantNotificationInfo = tenantNotificationInfo };

            //TODO:根据传入的参数添加过滤条件

            #region 权限验证

            var userID = AbpSession.GetUserId();
            query = query.Where(p => p.tenantNotificationInfo.CreatorUserId == userID);

            #endregion

            if (!string.IsNullOrWhiteSpace(input.Filter))
                query = query.Where(p => p.tenantNotificationInfo.Data.Contains(input.Filter));

            var totalCount = await query.CountAsync();

            var unreadCount = await query.CountAsync();

            var notifications = await GetUserNotificationsAsync(input.SkipCount, input.MaxResultCount, input.Filter);
            var userList = _userRepository.GetAll();

            var list = notifications.MapTo<List<UserNotificationExtend>>();
            foreach (var item in list)
            {
                var userModel = userList.Where(p => p.Id == item.UserId).FirstOrDefault();
                if (userModel != null)
                    item.Name = userModel.Name;
            }

            return new GetNotificationsExtendOutput(totalCount, unreadCount, list);
        }


        /// <summary>
        /// 根据UserId获取消息通知列表
        /// </summary>
        [AbpAuthorize]
        public async Task<GetNotificationsExtendOutput> GetUserNotificationsByUserIdAsync(GetUserNotificationsInput input)
        {
            var query = from userNotificationInfo in _userNotificationRepository.GetAll()
                        join tenantNotificationInfo in _tenantNotificationRepository.GetAll() on userNotificationInfo.TenantNotificationId equals tenantNotificationInfo.Id
                        orderby tenantNotificationInfo.CreationTime descending
                        select new { userNotificationInfo, tenantNotificationInfo = tenantNotificationInfo };

            //TODO:根据传入的参数添加过滤条件
            if (input.UserID > 0)
            {
                query = query.Where(p => p.userNotificationInfo.UserId == input.UserID);
            }

            if (!string.IsNullOrWhiteSpace(input.EntityId))
            {
                query = query.Where(p => p.tenantNotificationInfo.EntityId == input.EntityId);
            }

            if (!string.IsNullOrWhiteSpace(input.Filter))
                query = query.Where(p => p.tenantNotificationInfo.Data.Contains(input.Filter));

            var totalCount = await query.CountAsync();

            var unreadCount = await query.CountAsync();

            var notifications = await GetUserNotificationsAsync(input.SkipCount, input.MaxResultCount, input.Filter, input.UserID, input.EntityId);
            var userList = _userRepository.GetAll();

            var list = notifications.MapTo<List<UserNotificationExtend>>();
            foreach (var item in list)
            {
                var userModel = userList.Where(p => p.Id == item.UserId).FirstOrDefault();
                if (userModel != null)
                    item.Name = userModel.Name;
            }

            return new GetNotificationsExtendOutput(totalCount, unreadCount, list);
        }

        public async Task<List<UserNotification>> GetUserNotificationsAsync(int skipCount = 0, int maxResultCount = int.MaxValue, string data = "", int UserID = 0, string EntityId = "")
        {
            var userNotifications = await GetUserNotificationsWithNotificationsAsync(skipCount, maxResultCount, data, UserID, EntityId);
            return userNotifications
                .Select(un => un.ToUserNotification())
                .ToList();
        }

        public virtual Task<List<UserNotificationInfoWithNotificationInfo>> GetUserNotificationsWithNotificationsAsync(int skipCount = 0, int maxResultCount = int.MaxValue, string data = "", int UserID = 0, string EntityId = "")
        {
            var query = from userNotificationInfo in _userNotificationRepository.GetAll()
                        join tenantNotificationInfo in _tenantNotificationRepository.GetAll() on userNotificationInfo.TenantNotificationId equals tenantNotificationInfo.Id
                        orderby tenantNotificationInfo.CreationTime descending
                        select new { userNotificationInfo, tenantNotificationInfo = tenantNotificationInfo };

            #region 权限验证

            var userID = AbpSession.GetUserId();
            query = query.Where(p => p.tenantNotificationInfo.CreatorUserId == userID);

            #endregion

            if (!string.IsNullOrWhiteSpace(data))
                query = query.Where(p => p.tenantNotificationInfo.Data.Contains(data));

            if (UserID > 0)
            {
                query = query.Where(p => p.userNotificationInfo.UserId == UserID);
            }

            if (!string.IsNullOrWhiteSpace(EntityId))
            {
                query = query.Where(p => p.tenantNotificationInfo.EntityId == EntityId);
            }

            query = query.PageBy(skipCount, maxResultCount);

            var list = query.ToList();

            return Task.FromResult(list.Select(
                a => new UserNotificationInfoWithNotificationInfo(a.userNotificationInfo, a.tenantNotificationInfo)
                ).ToList());
        }

        /// <summary>
        /// 批量创建消息通知
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize]
        public async Task BatchCreateNotification(NotificationEditDto input)
        {
            if (input.TownID <= 0 && input.AreaID <= 0 && input.VillageID <= 0)
            {
                foreach (var item in input.UserIDs)
                {
                    var userModel = _userRepository.FirstOrDefault(item);
                    SentFrendshipRequestNotificationData model = new SentFrendshipRequestNotificationData() { MessageContent = input.Remark, MessageTitle = input.Title, User = userModel };
                    await _appNotifier.NewNoticeAsync(model);
                }
            }
            else
            {
                var query = _userRepository.GetAll();
                query = query.Where(q => q.UserType == "非群众");
                if (input.TownID > 0)
                    query = query.Where(p => p.TownID == input.TownID);
                if (input.AreaID > 0)
                    query = query.Where(p => p.AreaID == input.AreaID);
                if (input.VillageID > 0)
                    query = query.Where(p => p.VillageID == input.VillageID);
                var users = query.ToList();

                //PushMessage(input.Url, "a5cc3c6db0d991f94662b74406a2defe", FilterHtml.NoHTML(input.Remark));

                try
                {
                    Task.Factory.StartNew(delegate
                    {
                        var clientIDs = users.Where(u => !string.IsNullOrWhiteSpace(u.ClientID)).Select(u => u.ClientID).ToArray();
                        PushMessage(input.Url, string.Join(",", clientIDs), input.Title, FilterHtml.NoHTML(input.Remark));
                    });
                }
                catch (Exception) { }

                foreach (var user in users)
                {
                    SentFrendshipRequestNotificationData model = new SentFrendshipRequestNotificationData() { MessageContent = input.Remark, MessageTitle = input.Title, User = user };
                    await _appNotifier.NewNoticeAsync(model);
                }
            }
        }

        private void PushMessage(string url, string clientIDs, string title, string content)
        {
            if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(clientIDs) || string.IsNullOrWhiteSpace(content)) return;

            Encoding encoding = Encoding.UTF8;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.ContentType = "application/json";

            var str = "{title:\"" + title + "\",content:\"" + content + "\",clientIDs:\"" + clientIDs + "\"}";
            byte[] data = encoding.GetBytes(str);
            request.ContentLength = data.Length;

            request.GetRequestStream().Write(data, 0, data.Length);
            request.GetResponse();
        }

        /// <summary>
        /// 根据userNotificationId获取消息通知
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize]
        public async Task<UserNotification> GetUserNotificationByIdAsync(GetUserNotificationByIdInput input)
        {
            return await _userNotificationManager.GetUserNotificationAsync(input.TenantId, input.UserNotificationId);
        }

        /// <summary>
        /// 根据userNotificationId删除消息通知
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize]
        public async Task DeleteUserNotificationByIdAsync(GetUserNotificationByIdInput input)
        {
            await _userNotificationManager.DeleteUserNotificationAsync(input.TenantId, input.UserNotificationId);
        }

        #endregion

        #region 消息通知管理

        [DisableAuditing]
        public async Task<GetNotificationsOutput> GetUserNotifications(GetUserNotificationsInput input)
        {
            var totalCount = await _userNotificationManager.GetUserNotificationCountAsync(
                AbpSession.ToUserIdentifier(), input.State
                );

            var unreadCount = await _userNotificationManager.GetUserNotificationCountAsync(
                AbpSession.ToUserIdentifier(), UserNotificationState.Unread
                );

            var notifications = await _userNotificationManager.GetUserNotificationsAsync(
                AbpSession.ToUserIdentifier(), input.State, input.SkipCount, input.MaxResultCount
                );

            return new GetNotificationsOutput(totalCount, unreadCount, notifications);
        }

        public async Task SetAllNotificationsAsRead()
        {
            await _userNotificationManager.UpdateAllUserNotificationStatesAsync(AbpSession.ToUserIdentifier(), UserNotificationState.Read);
        }

        public async Task SetNotificationAsRead(EntityDto<Guid> input)
        {
            var userNotification = await _userNotificationManager.GetUserNotificationAsync(AbpSession.TenantId, input.Id);
            if (userNotification.UserId != AbpSession.GetUserId())
            {
                throw new ApplicationException(string.Format("Given user notification id ({0}) is not belong to the current user ({1})", input.Id, AbpSession.GetUserId()));
            }

            await _userNotificationManager.UpdateUserNotificationStateAsync(AbpSession.TenantId, input.Id, UserNotificationState.Read);
        }

        public async Task<GetNotificationSettingsOutput> GetNotificationSettings()
        {
            var output = new GetNotificationSettingsOutput();

            output.ReceiveNotifications = await SettingManager.GetSettingValueAsync<bool>(NotificationSettingNames.ReceiveNotifications);

            output.Notifications = (await _notificationDefinitionManager
                .GetAllAvailableAsync(AbpSession.ToUserIdentifier()))
                .Where(nd => nd.EntityType == null) //Get general notifications, not entity related notifications.
                .MapTo<List<NotificationSubscriptionWithDisplayNameDto>>();

            var subscribedNotifications = (await _notificationSubscriptionManager
                .GetSubscribedNotificationsAsync(AbpSession.ToUserIdentifier()))
                .Select(ns => ns.NotificationName)
                .ToList();

            output.Notifications.ForEach(n => n.IsSubscribed = subscribedNotifications.Contains(n.Name));

            return output;
        }

        public async Task UpdateNotificationSettings(UpdateNotificationSettingsInput input)
        {
            await SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), NotificationSettingNames.ReceiveNotifications, input.ReceiveNotifications.ToString());

            foreach (var notification in input.Notifications)
            {
                if (notification.IsSubscribed)
                {
                    await _notificationSubscriptionManager.SubscribeAsync(AbpSession.ToUserIdentifier(), notification.Name);
                }
                else
                {
                    await _notificationSubscriptionManager.UnsubscribeAsync(AbpSession.ToUserIdentifier(), notification.Name);
                }
            }
        }

        #endregion

        #region APP接口

        /// <summary>
        /// 根据查询条件获取消息通知分页列表
        /// </summary>
        public async Task<PagedResultDto<UserNotificationAPP>> GetPagedNotificationAPPAsync(GetUserNotificationsAPPInput input)
        {
            var _userID = Convert.ToInt32(input.UserID);
            var user = _userRepository.GetAll().Where(p => p.Id == _userID).FirstOrDefault();
            var totalCount = await _userNotificationManager.GetUserNotificationCountAsync(
                user.ToUserIdentifier(), null
                );

            int SkipCount = Convert.ToInt32(input.PageSize) * (Convert.ToInt32(input.PageIndex) - 1);

            var notifications = await _userNotificationManager.GetUserNotificationsAsync(
                 user.ToUserIdentifier(), null, SkipCount, Convert.ToInt32(input.PageSize)
                );

            return new PagedResultDto<UserNotificationAPP>(totalCount,
                notifications.Select(item =>
                {
                    var dto = new UserNotificationAPP();
                    Dictionary<string, object> dic = item.Notification.Data.Properties;
                    dto.Id = item.Id;
                    //拓展属性Message存放标题，content存放消息内容
                    if (dic["Message"] != null)
                        dto.Title = dic["Message"].ToString();

                    dto.CreationTime = AppSetting.ConvertIntDatetime(Convert.ToDateTime(item.Notification.CreationTime)).ToString();

                    return dto;
                }).ToList());
        }

        public async Task<UserNotificationSingleAPP> GetNotificationByIDAPPAsync(GetUserNotificationByIdInput input)
        {
            var _userID = Convert.ToInt32(input.UserID);
            var user = _userRepository.GetAll().Where(p => p.Id == _userID).FirstOrDefault();
            var notifications = await _userNotificationManager.GetUserNotificationAsync(user.TenantId, input.UserNotificationId);
            Dictionary<string, object> dic = notifications.Notification.Data.Properties;

            var dto = new UserNotificationSingleAPP();
            //拓展属性Message存放标题，content存放消息内容
            if (dic["Message"] != null)
                dto.Title = dic["Message"].ToString();
            //拓展属性Message存放标题，content存放消息内容
            if (dic["content"] != null)
                dto.Message = dic["content"].ToString();

            dto.CreationTime = AppSetting.ConvertIntDatetime(Convert.ToDateTime(notifications.Notification.CreationTime)).ToString();

            return dto;
        }

        #endregion

    }
}